package util

import (
	"auto-wallpaper/profile"
	"bytes"
	"errors"
	"fmt"
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"
)

var num int = 0

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	fmt.Println("正在执行....")

}

// SaveUserPics 下载图片
func SaveUserPics(picUrlList []string, basePath string, cover bool, sleep int, hadDown chan<- string) {
	err := MakeDir(basePath)
	if err != nil {
		fmt.Println(err)
	}
	var errs []error
	for _, picUrl := range picUrlList {
		fileName := NameByUrl(picUrl)
		filePath := basePath + "/" + fileName

		done, err := Down(cover, filePath, picUrl, sleep, hadDown, fileName)
		if err != nil {
			errs = append(errs, err)
		}
		if done {
			return
		}

	}
	defer func() {
		if hadDown != nil {
			close(hadDown)
		}
	}()
}

func Down(cover bool, filePath string, picUrl string, sleep int, hadDown chan<- string, fileName string) (bool, error) {
	if cover || !FileIsExisted(filePath) {
		fmt.Println("-------------------下载图片开始: " + picUrl + "---------------------------------------")
		defer fmt.Println("-------------------下载图片结束: " + picUrl + "---------------------------------------")
		fmt.Println("下载图片： " + picUrl)
		if sleep > 0 {
			time.Sleep(time.Millisecond * time.Duration(sleep))
		}
		resp, err := http.Get(picUrl)
		if err != nil {
			return true, err
		}
		var delete = false
		defer func() {
			if delete {
				err := os.Remove(filePath)
				fmt.Println(err)
			}
		}()
		defer resp.Body.Close()
		fmt.Println("下载图片状态： " + resp.Status)

		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			fmt.Print("读取byte： ")
			fmt.Println(err)
			return false, err
		}
		out, err := os.Create(filePath)
		if err != nil {
			return false, err
		}
		defer out.Close()
		if cover {
			os.Remove(filePath)
		}
		_, err = io.Copy(out, bytes.NewReader(body))
		if err != nil {
			return false, err
		}
		if resp.Body != nil {
			resp.Body.Close()
		}

		file, err := os.Open(filePath)

		if err != nil {
			fmt.Printf("打开文件失败： %v\n", err)
			delete = true
		}
		defer file.Close()
		m, _, err := image.Decode(file)
		if err != nil {
			fmt.Print("image.Decode： ")
			fmt.Println(err)
			delete = true
			return false, err
		}
		defer file.Close()
		// 读取分辨率
		rectangle := m.Bounds()
		x := rectangle.Max.X
		y := rectangle.Max.Y
		fmt.Printf("x = %v, y=%v", x, y)
		if profile.AppConfigSet.MinPixel > 1 && x*y < profile.AppConfigSet.MinPixel {
			fmt.Printf("像素过低 %v(x*y)  < %v(MinPixel)\n", x*y, profile.AppConfigSet.MinPixel)
			delete = true
			return false, fmt.Errorf("像素过低")
		}
		if profile.AppConfigSet.MaxPixel > 1 && x*y > profile.AppConfigSet.MaxPixel {
			fmt.Printf("像素过高 %v(x*y)  > %v(MaxPixel)\n", x*y, profile.AppConfigSet.MaxPixel)
			delete = true
			return false, fmt.Errorf("像素过高")
		}
		if profile.AppConfigSet.MinRatio > 0.01 && float64(x)/float64(y) < profile.AppConfigSet.MinRatio {
			fmt.Printf("尺寸比例过小 %v(x/y)  < %v(MinRatio)\n", x/y, profile.AppConfigSet.MinRatio)
			delete = true
			return false, fmt.Errorf("尺寸比例过小")
		}
		if profile.AppConfigSet.MaxRatio > 0.01 && float64(x)/float64(y) > profile.AppConfigSet.MaxRatio {
			fmt.Printf("尺寸比例过大 %v(x/y)  > %v(MaxRatio)\n", x*y, profile.AppConfigSet.MaxRatio)
			delete = true
			return false, fmt.Errorf("尺寸比例过大")
		}

		if len(body) < profile.AppConfigSet.MinSize {
			fmt.Printf("文件过小 %vb  > %vb", len(body), profile.AppConfigSet.MinSize)
			delete = true
			return false, err
		}
		fmt.Println("复制完成")
	} else {

		fmt.Println("图片已下载 : " + fileName)
	}
	defer func() {
		if hadDown != nil {
			hadDown <- filePath
		}
	}()

	return true, nil
}

func NameByUrl(url string) string {
	fields := strings.Split(url, "/")
	if len(fields) > 0 {
		return fields[len(fields)-1]
	}
	return ""
}

func MvFile(source string, target string) error {
	tp := target + "/" + strconv.Itoa(time.Now().Nanosecond())
	_ = MakeDir(tp)
	err := CopyDirFile(source, tp)
	if err != nil {
		return err
	}
	// 尝试删除所有旧文件
	files, err := ListDir(source, "")
	if err != nil {
		return err
	}
	// 删除旧文件
	var errs []error
	for _, f := range files {
		err := os.Remove(f)
		errs = append(errs, err)
	}
	return fmt.Errorf("%v", errs)
}

func CopyDirFile(source string, tp string) error {

	files, err := ListDir(source, "")
	if err != nil {
		return err
	}
	var errs []error
	for _, f := range files {
		fileName := NameByUrl(f)
		_, err := CopyFile(f, tp+"/"+fileName)
		if err != nil {
			errs = append(errs, err)
		}
	}
	if len(errs) <= 0 {
		return nil
	}
	return fmt.Errorf("%v", errs)
}

func CopyDir(srcPath, desPath string) error {
	//检查目录是否正确
	if srcInfo, err := os.Stat(srcPath); err != nil {
		return err
	} else {
		if !srcInfo.IsDir() {
			return errors.New("源路径不是一个正确的目录！")
		}
	}

	if desInfo, err := os.Stat(desPath); err != nil {
		return err
	} else {
		if !desInfo.IsDir() {
			return errors.New("目标路径不是一个正确的目录！")
		}
	}

	if strings.TrimSpace(srcPath) == strings.TrimSpace(desPath) {
		return errors.New("源路径与目标路径不能相同！")
	}

	err := filepath.Walk(srcPath, func(path string, f os.FileInfo, err error) error {
		if f == nil {
			return err
		}

		//复制目录是将源目录中的子目录复制到目标路径中，不包含源目录本身
		if path == srcPath {
			return nil
		}

		//生成新路径
		destNewPath := strings.Replace(path, srcPath, desPath, -1)

		if !f.IsDir() {
			CopyFile(path, destNewPath)
		} else {
			if !FileIsExisted(destNewPath) {
				return MakeDir(destNewPath)
			}
		}

		return nil
	})

	return err
}

func CopyFile(src, des string) (written int64, err error) {
	srcFile, err := os.Open(src)
	if err != nil {
		return 0, err
	}
	defer srcFile.Close()

	//获取源文件的权限
	fi, _ := srcFile.Stat()
	perm := fi.Mode()

	//desFile, err := os.Create(des)  //无法复制源文件的所有权限
	desFile, err := os.OpenFile(des, os.O_RDWR|os.O_CREATE|os.O_TRUNC, perm) //复制源文件的所有权限
	if err != nil {
		return 0, err
	}
	defer desFile.Close()

	return io.Copy(desFile, srcFile)
}

func FileIsExisted(filename string) bool {
	existed := true
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		existed = false
	}
	return existed
}

func MakeDir(dir string) error {
	if !FileIsExisted(dir) {
		if err := os.MkdirAll(dir, 0777); err != nil { //os.ModePerm
			fmt.Println("MakeDir failed:", err)
			return err
		}
	}
	return nil
}

// ListDir  获取指定路径下的所有文件，只搜索当前路径，不进入下一级目录，可匹配后缀过滤（suffix为空则不过滤）
func ListDir(dir, suffix string) (files []string, err error) {
	files = []string{}

	_dir, err := ioutil.ReadDir(dir)
	if err != nil {
		return nil, err
	}

	suffix = strings.ToLower(suffix) //匹配后缀

	for _, _file := range _dir {
		if _file.IsDir() {
			continue //忽略目录
		}
		if len(suffix) == 0 || strings.HasSuffix(strings.ToLower(_file.Name()), suffix) {
			//文件后缀匹配
			files = append(files, path.Join(dir, _file.Name()))
		}
	}

	return files, nil
}
